package org.ws.httphelper.support;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ws.httphelper.HttpHelper;
import org.ws.httphelper.core.fetcher.HttpFetcher;
import org.ws.httphelper.core.pipeline.HttpPipeline;
import org.ws.httphelper.model.RequestContext;
import org.ws.httphelper.model.http.RequestData;
import org.ws.httphelper.model.http.ResponseData;
import org.ws.httphelper.model.http.ResponseFuture;
import org.ws.httphelper.model.template.RequestTemplate;
import org.ws.httphelper.support.fetcher.FetcherPool;
import org.ws.httphelper.support.pipeline.DefaultHttpPipeline;

import java.util.function.Consumer;

/**
 * 默认的HttpHelper实现。
 * 每一个HttpHelper包括抓取器和请求模版
 */
public class DefaultHttpHelper implements HttpHelper {

    private static Logger log = LoggerFactory.getLogger(DefaultHttpHelper.class.getName());
    /**
     * 执行http请求的抓取器
     */
    private final HttpFetcher httpFetcher;
    /**
     * 请求模版
     */
    private final RequestTemplate template;

    public DefaultHttpHelper(RequestTemplate template) {
        this.template = template;
        // 根据client配置生成抓取器
        // 若是私有client：每一个httpHelper都有自己唯一的client
        // 若是共有client：则从FetcherPool中获取一个有相同配置的client
        this.httpFetcher = FetcherPool.getInstance().getHttpFetcher(template.getClientConfig());
    }

    @Override
    public ResponseFuture request(String url) {
        return request(url,null);
    }

    @Override
    public ResponseFuture request(String url, Object input) {
        return request(url,input,null);
    }

    @Override
    public <T> ResponseFuture<T> request(String url, Object input, Class<T> outputClass) {
        // 生成context
        // 每一个请求都会生成一个新的context
        RequestContext context = new RequestContext(url, input, this.template.getRequestConfig());
        // 设置响应类型
        context.setOutputClass(outputClass);
        return doRequest(context);
    }

    @Override
    public void requestAsync(String url, Consumer<ResponseFuture<Object>> callback) {
        requestAsync(url,null,callback);
    }

    @Override
    public void requestAsync(String url, Object input, Consumer<ResponseFuture<Object>> callback) {
        requestAsync(url,input,callback,null);
    }

    @Override
    public <T> void requestAsync(String url, Object input, Consumer<ResponseFuture<T>> callback, Class<T> outputClass) {
        RequestContext context = new RequestContext(url,input,this.template.getRequestConfig());
        context.setOutputClass(outputClass);
        doRequestAsync(context,callback);
    }

    @Override
    public HttpPipeline pipeline() {
        return this.template.getRequestConfig().getHttpPipeline();
    }

    @Override
    public RequestTemplate template() {
        return this.template;
    }

    /**
     * 执行同步请求
     * @param context
     * @return
     */
    private ResponseFuture doRequest(final RequestContext context){
        // 获取pipeline
        DefaultHttpPipeline httpPipeline = (DefaultHttpPipeline)context.getHttpPipeline();
        RequestData requestData = context.getRequestData();
        ResponseFuture responseFuture = new ResponseFuture(requestData);
        try {
            // pipeline执行所有配置的RequestHandler处理器：主要是生成ResponseData
            httpPipeline.request(context);
            // 执行请求
            ResponseData responseData = httpFetcher.fetch(requestData);
            // 将获取的响应设置到返回对象
            responseFuture.setResponseData(responseData);
            responseFuture.setSuccess(responseData.isSuccessful());
        } catch (Exception e) {
            // 执行失败
            responseFuture.setSuccess(false);
            responseFuture.setError(e);
            log.error(e.getMessage(),e);
        }
        finally {
            context.setResponseFuture(responseFuture);
            // pipeline执行所有配置的ResponseHandler处理器：主要是解析响应或存储数据
            httpPipeline.response(context);
        }
        return responseFuture;
    }

    /**
     * 执行异步请求
     * @param context 请求上下文
     * @param callback 回调
     * @param <T>
     */
    private <T> void doRequestAsync(final RequestContext context,final Consumer<ResponseFuture<T>> callback){
        final DefaultHttpPipeline httpPipeline = (DefaultHttpPipeline)context.getHttpPipeline();
        final RequestData requestData = context.getRequestData();
        // pipeline执行所有配置的RequestHandler处理器：主要是生成ResponseData
        httpPipeline.request(context);
        httpFetcher.fetch(requestData,responseFuture -> {
            try {
                context.setResponseFuture(responseFuture);
                // 无论如何都会执行响应后处理
                // pipeline执行所有配置的ResponseHandler处理器：主要是解析响应或存储数据
                httpPipeline.response(context);
            }
            finally {
                // 无论httpPipeline.response是否执行失败都会执行回调处理
                callback.accept(responseFuture);
            }
        });
    }
}
